# load necessary packages
library(tidyverse)
library(mosaic)
library(DataComputing)
library(ggplot2)

Guiding Question

What factors are common between all hall of fame MLB baseball players? Hall of Fame baseball players are obviously a step ahead of everybody else. They are considered great players and have a knack for understanding the game. Becoming a Hall of Fame baseball player is no easy feat. They have advanced stats that show how great the players truly are; but what enables a baseball player to be inducted into the Hall of Fame? We are going to dive deep and see the comparisons between inducted Hall of Fame players and other players who tried to live up to the legendary names. Some challenges we faced with some of the data sets was that some of the data sets had incompleteness in the data. For some of the players from the older years, some statistics were not tracked because of the inconsistency of recording data during these years. Some stats are currently tracked through computers which were not accessible at some years shown in the data sets. Another problem we faced was the lack of explanation of some data. Some players were repeated twice for certain years in categories that should not show repetition. This throws the numbers we tracked off by a few, but did not skew the results too much, luckily. One finding that we found to be significant was the amount of times that inducted players had a batting average over .5 (500). This is no easy feat as it means that at least half of the players hits got them on a base through the whole year. The most shocking part about this data is how high the numbers got to be. We made sure that players played in at least 20 games, and players were still hitting over .65 (650). This shows how excellent these players were at the time and through certain years.

Data Access

HallOfFame <- read_csv("core/HallOfFame.csv")
Parsed with column specification:
cols(
  playerID = col_character(),
  yearID = col_double(),
  votedBy = col_character(),
  ballots = col_double(),
  needed = col_double(),
  votes = col_double(),
  inducted = col_character(),
  category = col_character(),
  needed_note = col_character()
)
AllstarFull <- read_csv("core/AllstarFull.csv")
Parsed with column specification:
cols(
  playerID = col_character(),
  yearID = col_double(),
  gameNum = col_double(),
  gameID = col_character(),
  teamID = col_character(),
  lgID = col_character(),
  GP = col_double(),
  startingPos = col_double()
)
Salaries <- read_csv("core/Salaries.csv")
Parsed with column specification:
cols(
  yearID = col_double(),
  teamID = col_character(),
  lgID = col_character(),
  playerID = col_character(),
  salary = col_double()
)
Batting <- read_csv("core/Batting.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  playerID = col_character(),
  teamID = col_character(),
  lgID = col_character(),
  IBB = col_logical(),
  HBP = col_logical(),
  SH = col_logical(),
  SF = col_logical()
)
See spec(...) for full column specifications.
87292 parsing failures.
 row col           expected actual               file
1999 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2001 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2020 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2022 HBP 1/0/T/F/TRUE/FALSE      2 'core/Batting.csv'
2027 HBP 1/0/T/F/TRUE/FALSE      5 'core/Batting.csv'
.... ... .................. ...... ..................
See problems(...) for more details.
head(HallOfFame)
glimpse(HallOfFame)
Observations: 4,191
Variables: 9
$ playerID    <chr> "cobbty01", "ruthba01", "wagneho01", "mathech01", "johnswa01", "lajoina01", "speaktr01…
$ yearID      <dbl> 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 19…
$ votedBy     <chr> "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWAA", "BBWA…
$ ballots     <dbl> 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 7…
$ needed      <dbl> 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 5…
$ votes       <dbl> 222, 215, 215, 205, 189, 146, 133, 111, 105, 80, 77, 60, 58, 55, 51, 47, 40, 39, 39, 3…
$ inducted    <chr> "Y", "Y", "Y", "Y", "Y", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "…
$ category    <chr> "Player", "Player", "Player", "Player", "Player", "Player", "Player", "Player", "Playe…
$ needed_note <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
head(Salaries)
glimpse(Salaries)
Observations: 26,428
Variables: 5
$ yearID   <dbl> 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985, 1985,…
$ teamID   <chr> "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL", "ATL"…
$ lgID     <chr> "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL",…
$ playerID <chr> "barkele01", "bedrost01", "benedbr01", "campri01", "ceronri01", "chambch01", "dedmoje01",…
$ salary   <dbl> 870000, 550000, 545000, 633333, 625000, 800000, 150000, 483333, 772000, 250000, 1500000, …
head(Batting)
head(AllstarFull)
glimpse(AllstarFull)
Observations: 5,375
Variables: 8
$ playerID    <chr> "gomezle01", "ferreri01", "gehrilo01", "gehrich01", "dykesji01", "cronijo01", "chapmbe…
$ yearID      <dbl> 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 19…
$ gameNum     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ gameID      <chr> "ALS193307060", "ALS193307060", "ALS193307060", "ALS193307060", "ALS193307060", "ALS19…
$ teamID      <chr> "NYA", "BOS", "NYA", "DET", "CHA", "WS1", "WS1", "CHA", "NYA", "CLE", "WS1", "NYA", "C…
$ lgID        <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "A…
$ GP          <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ startingPos <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1, 2, 3, 4, 5, 6, 7, 8,…

Data Wrangling

This will filter will allow us to see the player and the year that they were inducted into the hall of fame.

InductedP<-
  HallOfFame%>%
  filter(inducted == "Y")%>%
  select(playerID, yearID)
InductedP

Using the Inducted table we created this ExperienceHP separate hall of fame player that played more than 2000 games. In our analysis, we chose to say that if a player played more than 2000 games, that these player we Experienced. To compare the experienced players with the other player in the hall of fame, we made the player that played less than 2000 games inexperenced.

ExperiencedHP<-
  InductedP%>%
  left_join(Batting, by = c("playerID" = "playerID"))%>%
  group_by(playerID)%>%
  summarise(Total_Games = sum(G))%>%
  filter(Total_Games >= 2000)%>%
  mutate(Total_Games = "Experienced")
ExperiencedHP
InexperiencedHP<-
  InductedP%>%
  left_join(Batting, by = c("playerID" = "playerID"))%>%
  group_by(playerID)%>%
  summarise(Total_Games = sum(G))%>%
  filter(Total_Games <= 2000)%>%
  mutate(Total_Games = "Inexperienced")
  
InexperiencedHP

This join will us to see the year that the player was inducted into the hall of fame for further analysis.

EXYear<-
  ExperiencedHP%>%
  left_join(InductedP, by =c("playerID" = "playerID"))
EXYear
InexYear<-
  InexperiencedHP%>%
  left_join(InductedP, by =c("playerID" = "playerID"))
InexYear

We summarised the sum of each player’s salary to use to match their experience levels.

Money<-
  Salaries%>%
  select(playerID, salary)%>%
  group_by(playerID)%>%
  summarise(Salary = sum(salary))
Money

These joins matched the playerID for us to make a ggplot about the data.

HallMoney<-
  EXYear%>%
  left_join(Money, by = c("playerID" = "playerID"))
HallMoney
HallMoneyC<-
  InexYear%>%
  left_join(Money, by = c("playerID" = "playerID"))
HallMoneyC

This join combined the Inexperienced players as well as the experienced players to be able to plot.

AllHall<-
  HallMoney%>%
  full_join(HallMoneyC, by = c("playerID", "Total_Games", "yearID", "Salary"))
AllHall

We took the whole league and seperated players who were not inducted into the Hall of Fame. Then, we took those players and seperated them into 2 groups. One group was the experienced group who have players who player more than 2000 games. The other group is not experienced players who played less than 2000 games.

#Players in the whole league
WholeLeague <-
  Batting %>%
  filter(G > 20)%>%
  group_by(playerID)%>%
  summarise(Total_Games = sum(G))
NotInd<-
  WholeLeague%>%
  inner_join(HallOfFame, by =c("playerID" = "playerID"))%>%
  filter(inducted == "N")%>%
  group_by(playerID)%>%
  summarise(Total_Games = sum(Total_Games))
NewB<- 
  NotInd%>%
  filter(Total_Games <= 2000)%>%
  mutate(Total_Games = "Not Experienced")
NotNewB<-
  NotInd%>%
  filter(Total_Games >= 2000)%>%
  mutate(Total_Games = "Experienced")

This data wrangling shows the salary for the whole league, but it is split up into the experienced and not experienced players.

AllLeague<-
  NewB%>%
  full_join(NotNewB, by = c("playerID", "Total_Games"))
AllLeague
  
AllLM<- 
  AllLeague%>%
  left_join(Money, by = c("playerID" = "playerID"))
AllLM
TotLeague<-
  AllLM%>%
  left_join(HallOfFame, by = c("playerID" = "playerID"))%>%
  filter(inducted == "N")%>%
  select(playerID, yearID, Total_Games, Salary)
TotLeague

This join operation will join the HallOfFame table with the AllstarFull table to help us find the correlation between the players that made the Hall Of Fame and played in All Star Games. We can use this joined data set to figure out commonalities between all of the Hall Of Fame baseball players.

# Join the AllstarFull table with the HallOfFame table
AllStarHallOfFameJoin <-
  AllstarFull %>%
  inner_join(HallOfFame, by = c("playerID" = "playerID"))
# Use data wrangling to alter the table to find the amount of times an inducted players played in All Star Games
AllStarHallOfFameTable <-
  AllStarHallOfFameJoin %>%
  filter(inducted == "Y") %>%
  group_by(playerID, inducted) %>%
  summarise(AppearanceCount = n()) %>%
  arrange(desc(AppearanceCount))
  
AllStarHallOfFameTable

This ggplot shows the correlation between experienced and inexperienced hall of fame playeres. We have filled their color by their experience. The plot on the graph is correlated to the year that they were inducted.

AllHall%>%
ggplot(aes(x = yearID, y = Salary, color = Total_Games))+
   geom_point()+
   geom_smooth()+
  labs(x = "Year Inducted", y = "Total Salary", Total_Games = "Experience Level")

This plot displays the salaries of all the players in the league that were not inducted into the hall of fame. We can see that in this plot the players with more experience are recieving more money. To compare with the hall of fame players, we can see that some players that are not inducted to the league are recievving more money. However, it our dataset some salaries were missig which can have player with higher salaries in the hall of fame and just in the league.

TotLeague%>%
ggplot(aes(x = yearID, y = Salary, color = Total_Games))+
   geom_point()+
   geom_smooth()+
  labs(x = "Year", y = "Total Salary (Millions)")

The table displayed below uses regular expressions to display the inducted Hall of Fame players who had a batting average of 500 or more in at least 20 games and years that made the achievement. This helps show how good the inducted players are at batting and the years that they did it in.

HallOfFamePlayers <-
  HallOfFame %>%
  filter(inducted == "Y") %>%
  select(playerID, yearID)
HallOfFameBatting <-
  Batting %>%
  inner_join(HallOfFamePlayers, by = c("playerID" = "playerID"))
HallOfFameBatAvg <-
  HallOfFameBatting %>%
  filter(G > 20) %>%
  select(playerID, yearID.x, AB)
HallOfFameOver500 <-
  HallOfFameBatAvg %>%
  extractMatches("^([5-9]{1}[0-9]{2}).*$", AB) %>%
  filter( ! is.na(match1))
HallOfFameOver500

The graph below is the comparison between inducted Hall of Fame Players. This graph displays the amount of players that played in certain amount of All Star Games, indicated along the x-axis. This graph has a y-intercept of the average amount of appearances. This average line helps us understand how important All Star appearances were for players being inducted into Hall of Fame.

AllStarHallOfFameGraphData <-
  AllStarHallOfFameTable %>%
  group_by(AppearanceCount) %>%
  summarise(total = n())
AllStarHallOfFameGraph <-
  AllStarHallOfFameGraphData %>%
  ggplot(aes(x = AppearanceCount, y = total)) +
  geom_bar(stat = "identity", color = "black", fill = "red") +
  geom_hline(aes(yintercept = mean(total)), color = "blue")
AllStarHallOfFameGraph

In the graph below, you can notice that the avg homeruns per year of Hall of Famers is lower than the rest of the league. This would indicate that Homeruns are not a crucial statistic in the game of baseball to get you into the Hall of Fame.

#Batting stats
BattingAndHallofFame <- 
  Batting %>%
  full_join(HallOfFame, by = c("playerID" = "playerID")) %>%
  filter(inducted == "Y")
#Only Take stats with players having more than 20 games
BattingAndHallofFame <-
  BattingAndHallofFame %>%
    filter(G > 20) 
HallOfFamerHomies <-
  BattingAndHallofFame %>%
    select(yearID.x, H) %>%
    group_by(yearID.x) %>%
    summarise(AvgHsHOF = mean(H)) %>%
    rename(yearID = yearID.x)
EverybodyBatting <-
  Batting %>%
    filter(G > 20) %>%
    summarise(AvgHomeRunPerPlayerEverybody = mean(H))
GraphHomeRuns <-
  Batting %>%
    select(yearID, G, H) %>%
    group_by(yearID) %>%
    filter(G > 20) %>%
    summarise(AvgHsEvery = mean(H))
#Which league has greater HOF chance
LeagueFromAmerican <-
  BattingAndHallofFame %>%
    select(yearID.x, lgID) %>%
    group_by(yearID.x) %>%
    filter(lgID == "AA") %>%
    summarise(American = n()) %>%
    rename(yearID = yearID.x)
LeagueFromNational <-
  BattingAndHallofFame %>%
    select(yearID.x, lgID) %>%
    group_by(yearID.x) %>%
    filter(lgID == "NL") %>%
    summarise(National = n()) %>%
    rename(yearID = yearID.x)
LeagueGraph <-
  LeagueFromAmerican %>%
    full_join(LeagueFromNational, by = c("yearID" = "yearID"))
 
LeagueGraph1 <-
   LeagueGraph %>%
      gather(key = kind, value = Total, American, National)
LeagueGraph1
Graph1 <-
  GraphHomeRuns %>%
    full_join(HallOfFamerHomies, by = c("yearID" = "yearID"))
Graph1.1 <- 
  Graph1 %>%
    gather(key = kind, value = Avg, AvgHsHOF, AvgHsEvery)
ggplot(data=Graph1.1,aes(x=yearID,y=Avg ,fill=kind))+
  geom_bar(stat='identity',position='stack', width=.9)+
  ggtitle("HOF Vs Everybody Homeruns")

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCIKYXV0aG9yOiAiR3JvdXAgNTogTWF0dGhldyBIaW5lcywgRW1tYW51ZWwgR2Fyem8sIER1c3RpbiBCZWF2ZXIiCmRhdGU6ICI0LzI2LzIwMjAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgpgYGB7cn0KIyBsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkoRGF0YUNvbXB1dGluZykKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMjIyBHdWlkaW5nIFF1ZXN0aW9uCgpXaGF0IGZhY3RvcnMgYXJlIGNvbW1vbiBiZXR3ZWVuIGFsbCBoYWxsIG9mIGZhbWUgTUxCIGJhc2ViYWxsIHBsYXllcnM/IEhhbGwgb2YgRmFtZSBiYXNlYmFsbCBwbGF5ZXJzIGFyZSBvYnZpb3VzbHkgYSBzdGVwIGFoZWFkIG9mIGV2ZXJ5Ym9keSBlbHNlLiBUaGV5IGFyZSBjb25zaWRlcmVkIGdyZWF0IHBsYXllcnMgYW5kIGhhdmUgYSBrbmFjayBmb3IgdW5kZXJzdGFuZGluZyB0aGUgZ2FtZS4gQmVjb21pbmcgYSBIYWxsIG9mIEZhbWUgYmFzZWJhbGwgcGxheWVyIGlzIG5vIGVhc3kgZmVhdC4gVGhleSBoYXZlIGFkdmFuY2VkIHN0YXRzIHRoYXQgc2hvdyBob3cgZ3JlYXQgdGhlIHBsYXllcnMgdHJ1bHkgYXJlOyBidXQgd2hhdCBlbmFibGVzIGEgYmFzZWJhbGwgcGxheWVyIHRvIGJlIGluZHVjdGVkIGludG8gdGhlIEhhbGwgb2YgRmFtZT8gV2UgYXJlIGdvaW5nIHRvIGRpdmUgZGVlcCBhbmQgc2VlIHRoZSBjb21wYXJpc29ucyBiZXR3ZWVuIGluZHVjdGVkIEhhbGwgb2YgRmFtZSBwbGF5ZXJzIGFuZCBvdGhlciBwbGF5ZXJzIHdobyB0cmllZCB0byBsaXZlIHVwIHRvIHRoZSBsZWdlbmRhcnkgbmFtZXMuClNvbWUgY2hhbGxlbmdlcyB3ZSBmYWNlZCB3aXRoIHNvbWUgb2YgdGhlIGRhdGEgc2V0cyB3YXMgdGhhdCBzb21lIG9mIHRoZSBkYXRhIHNldHMgaGFkIGluY29tcGxldGVuZXNzIGluIHRoZSBkYXRhLiBGb3Igc29tZSBvZiB0aGUgcGxheWVycyBmcm9tIHRoZSBvbGRlciB5ZWFycywgc29tZSBzdGF0aXN0aWNzIHdlcmUgbm90IHRyYWNrZWQgYmVjYXVzZSBvZiB0aGUgaW5jb25zaXN0ZW5jeSBvZiByZWNvcmRpbmcgZGF0YSBkdXJpbmcgdGhlc2UgeWVhcnMuIFNvbWUgc3RhdHMgYXJlIGN1cnJlbnRseSB0cmFja2VkIHRocm91Z2ggY29tcHV0ZXJzIHdoaWNoIHdlcmUgbm90IGFjY2Vzc2libGUgYXQgc29tZSB5ZWFycyBzaG93biBpbiB0aGUgZGF0YSBzZXRzLiBBbm90aGVyIHByb2JsZW0gd2UgZmFjZWQgd2FzIHRoZSBsYWNrIG9mIGV4cGxhbmF0aW9uIG9mIHNvbWUgZGF0YS4gU29tZSBwbGF5ZXJzIHdlcmUgcmVwZWF0ZWQgdHdpY2UgZm9yIGNlcnRhaW4geWVhcnMgaW4gY2F0ZWdvcmllcyB0aGF0IHNob3VsZCBub3Qgc2hvdyByZXBldGl0aW9uLiBUaGlzIHRocm93cyB0aGUgbnVtYmVycyB3ZSB0cmFja2VkIG9mZiBieSBhIGZldywgYnV0IGRpZCBub3Qgc2tldyB0aGUgcmVzdWx0cyB0b28gbXVjaCwgbHVja2lseS4KT25lIGZpbmRpbmcgdGhhdCB3ZSBmb3VuZCB0byBiZSBzaWduaWZpY2FudCB3YXMgdGhlIGFtb3VudCBvZiB0aW1lcyB0aGF0IGluZHVjdGVkIHBsYXllcnMgaGFkIGEgYmF0dGluZyBhdmVyYWdlIG92ZXIgLjUgKDUwMCkuIFRoaXMgaXMgbm8gZWFzeSBmZWF0IGFzIGl0IG1lYW5zIHRoYXQgYXQgbGVhc3QgaGFsZiBvZiB0aGUgcGxheWVycyBoaXRzIGdvdCB0aGVtIG9uIGEgYmFzZSB0aHJvdWdoIHRoZSB3aG9sZSB5ZWFyLiBUaGUgbW9zdCBzaG9ja2luZyBwYXJ0IGFib3V0IHRoaXMgZGF0YSBpcyBob3cgaGlnaCB0aGUgbnVtYmVycyBnb3QgdG8gYmUuIFdlIG1hZGUgc3VyZSB0aGF0IHBsYXllcnMgcGxheWVkIGluIGF0IGxlYXN0IDIwIGdhbWVzLCBhbmQgcGxheWVycyB3ZXJlIHN0aWxsIGhpdHRpbmcgb3ZlciAuNjUgKDY1MCkuIFRoaXMgc2hvd3MgaG93IGV4Y2VsbGVudCB0aGVzZSBwbGF5ZXJzIHdlcmUgYXQgdGhlIHRpbWUgYW5kIHRocm91Z2ggY2VydGFpbiB5ZWFycy4KCgojIyMgRGF0YSBBY2Nlc3MKCmBgYHtyIExvYWRpbmcgdGhlIERhdGF9CgpIYWxsT2ZGYW1lIDwtIHJlYWRfY3N2KCJjb3JlL0hhbGxPZkZhbWUuY3N2IikKQWxsc3RhckZ1bGwgPC0gcmVhZF9jc3YoImNvcmUvQWxsc3RhckZ1bGwuY3N2IikKU2FsYXJpZXMgPC0gcmVhZF9jc3YoImNvcmUvU2FsYXJpZXMuY3N2IikKQmF0dGluZyA8LSByZWFkX2NzdigiY29yZS9CYXR0aW5nLmNzdiIpCgpgYGAKYGBge3J9CmhlYWQoSGFsbE9mRmFtZSkKYGBgCgoKYGBge3J9CmdsaW1wc2UoSGFsbE9mRmFtZSkKYGBgCgoKYGBge3J9CmhlYWQoU2FsYXJpZXMpCmBgYAoKCmBgYHtyfQpnbGltcHNlKFNhbGFyaWVzKQpgYGAKCgpgYGB7cn0KaGVhZChCYXR0aW5nKQpoZWFkKEFsbHN0YXJGdWxsKQpnbGltcHNlKEFsbHN0YXJGdWxsKQpgYGAKIyMjIERhdGEgV3JhbmdsaW5nCgpUaGlzIHdpbGwgZmlsdGVyIHdpbGwgYWxsb3cgdXMgdG8gc2VlIHRoZSBwbGF5ZXIgYW5kIHRoZSB5ZWFyIHRoYXQgdGhleSB3ZXJlIGluZHVjdGVkIGludG8gdGhlIGhhbGwgb2YgZmFtZS4gCmBgYHtyfQoKSW5kdWN0ZWRQPC0KICBIYWxsT2ZGYW1lJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJZIiklPiUKICBzZWxlY3QocGxheWVySUQsIHllYXJJRCkKCgpJbmR1Y3RlZFAKYGBgCgoKVXNpbmcgdGhlIEluZHVjdGVkIHRhYmxlIHdlIGNyZWF0ZWQgdGhpcyBFeHBlcmllbmNlSFAgc2VwYXJhdGUgaGFsbCBvZiBmYW1lIHBsYXllciB0aGF0IHBsYXllZCBtb3JlIHRoYW4gMjAwMCBnYW1lcy4gSW4gb3VyIGFuYWx5c2lzLCB3ZSBjaG9zZSB0byBzYXkgdGhhdCBpZiBhIHBsYXllciBwbGF5ZWQgbW9yZSB0aGFuIDIwMDAgZ2FtZXMsIHRoYXQgdGhlc2UgcGxheWVyIHdlIEV4cGVyaWVuY2VkLiBUbyBjb21wYXJlIHRoZSBleHBlcmllbmNlZCBwbGF5ZXJzIHdpdGggdGhlIG90aGVyIHBsYXllciBpbiB0aGUgaGFsbCBvZiBmYW1lLCB3ZSBtYWRlIHRoZSBwbGF5ZXIgdGhhdCBwbGF5ZWQgbGVzcyB0aGFuIDIwMDAgZ2FtZXMgaW5leHBlcmVuY2VkLiAKYGBge3J9CkV4cGVyaWVuY2VkSFA8LQogIEluZHVjdGVkUCU+JQogIGxlZnRfam9pbihCYXR0aW5nLCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKSU+JQogIGdyb3VwX2J5KHBsYXllcklEKSU+JQogIHN1bW1hcmlzZShUb3RhbF9HYW1lcyA9IHN1bShHKSklPiUKICBmaWx0ZXIoVG90YWxfR2FtZXMgPj0gMjAwMCklPiUKICBtdXRhdGUoVG90YWxfR2FtZXMgPSAiRXhwZXJpZW5jZWQiKQpFeHBlcmllbmNlZEhQCgpJbmV4cGVyaWVuY2VkSFA8LQogIEluZHVjdGVkUCU+JQogIGxlZnRfam9pbihCYXR0aW5nLCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKSU+JQogIGdyb3VwX2J5KHBsYXllcklEKSU+JQogIHN1bW1hcmlzZShUb3RhbF9HYW1lcyA9IHN1bShHKSklPiUKICBmaWx0ZXIoVG90YWxfR2FtZXMgPD0gMjAwMCklPiUKICBtdXRhdGUoVG90YWxfR2FtZXMgPSAiSW5leHBlcmllbmNlZCIpCiAgCkluZXhwZXJpZW5jZWRIUApgYGAKCgpUaGlzIGpvaW4gd2lsbCB1cyB0byBzZWUgdGhlIHllYXIgdGhhdCB0aGUgcGxheWVyIHdhcyBpbmR1Y3RlZCBpbnRvIHRoZSBoYWxsIG9mIGZhbWUgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuIApgYGB7cn0KRVhZZWFyPC0KICBFeHBlcmllbmNlZEhQJT4lCiAgbGVmdF9qb2luKEluZHVjdGVkUCwgYnkgPWMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKQpFWFllYXIKCkluZXhZZWFyPC0KICBJbmV4cGVyaWVuY2VkSFAlPiUKICBsZWZ0X2pvaW4oSW5kdWN0ZWRQLCBieSA9YygicGxheWVySUQiID0gInBsYXllcklEIikpCkluZXhZZWFyCmBgYAoKCldlIHN1bW1hcmlzZWQgdGhlIHN1bSBvZiBlYWNoIHBsYXllcidzIHNhbGFyeSB0byB1c2UgdG8gbWF0Y2ggdGhlaXIgZXhwZXJpZW5jZSBsZXZlbHMuIApgYGB7cn0KTW9uZXk8LQogIFNhbGFyaWVzJT4lCiAgc2VsZWN0KHBsYXllcklELCBzYWxhcnkpJT4lCiAgZ3JvdXBfYnkocGxheWVySUQpJT4lCiAgc3VtbWFyaXNlKFNhbGFyeSA9IHN1bShzYWxhcnkpKQoKTW9uZXkKYGBgCgoKVGhlc2Ugam9pbnMgbWF0Y2hlZCB0aGUgcGxheWVySUQgZm9yIHVzIHRvIG1ha2UgYSBnZ3Bsb3QgYWJvdXQgdGhlIGRhdGEuIApgYGB7cn0KSGFsbE1vbmV5PC0KICBFWFllYXIlPiUKICBsZWZ0X2pvaW4oTW9uZXksIGJ5ID0gYygicGxheWVySUQiID0gInBsYXllcklEIikpCkhhbGxNb25leQoKCkhhbGxNb25leUM8LQogIEluZXhZZWFyJT4lCiAgbGVmdF9qb2luKE1vbmV5LCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKQpIYWxsTW9uZXlDCgpgYGAKCgpUaGlzIGpvaW4gY29tYmluZWQgdGhlIEluZXhwZXJpZW5jZWQgcGxheWVycyBhcyB3ZWxsIGFzIHRoZSBleHBlcmllbmNlZCBwbGF5ZXJzIHRvIGJlIGFibGUgdG8gcGxvdC4gCmBgYHtyfQpBbGxIYWxsPC0KICBIYWxsTW9uZXklPiUKICBmdWxsX2pvaW4oSGFsbE1vbmV5QywgYnkgPSBjKCJwbGF5ZXJJRCIsICJUb3RhbF9HYW1lcyIsICJ5ZWFySUQiLCAiU2FsYXJ5IikpCkFsbEhhbGwKYGBgCgoKV2UgdG9vayB0aGUgd2hvbGUgbGVhZ3VlIGFuZCBzZXBlcmF0ZWQgcGxheWVycyB3aG8gd2VyZSBub3QgaW5kdWN0ZWQgaW50byB0aGUgSGFsbCBvZiBGYW1lLiBUaGVuLCB3ZSB0b29rIHRob3NlIHBsYXllcnMgYW5kIHNlcGVyYXRlZCB0aGVtIGludG8gMiBncm91cHMuIE9uZSBncm91cCB3YXMgdGhlIGV4cGVyaWVuY2VkIGdyb3VwIHdobyBoYXZlIHBsYXllcnMgd2hvIHBsYXllciBtb3JlIHRoYW4gMjAwMCBnYW1lcy4gVGhlIG90aGVyIGdyb3VwIGlzIG5vdCBleHBlcmllbmNlZCBwbGF5ZXJzIHdobyBwbGF5ZWQgbGVzcyB0aGFuIDIwMDAgZ2FtZXMuCmBgYHtyfQoKI1BsYXllcnMgaW4gdGhlIHdob2xlIGxlYWd1ZQpXaG9sZUxlYWd1ZSA8LQogIEJhdHRpbmcgJT4lCiAgZmlsdGVyKEcgPiAyMCklPiUKICBncm91cF9ieShwbGF5ZXJJRCklPiUKICBzdW1tYXJpc2UoVG90YWxfR2FtZXMgPSBzdW0oRykpCgpOb3RJbmQ8LQogIFdob2xlTGVhZ3VlJT4lCiAgaW5uZXJfam9pbihIYWxsT2ZGYW1lLCBieSA9YygicGxheWVySUQiID0gInBsYXllcklEIikpJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJOIiklPiUKICBncm91cF9ieShwbGF5ZXJJRCklPiUKICBzdW1tYXJpc2UoVG90YWxfR2FtZXMgPSBzdW0oVG90YWxfR2FtZXMpKQoKTmV3QjwtIAogIE5vdEluZCU+JQogIGZpbHRlcihUb3RhbF9HYW1lcyA8PSAyMDAwKSU+JQogIG11dGF0ZShUb3RhbF9HYW1lcyA9ICJOb3QgRXhwZXJpZW5jZWQiKQoKTm90TmV3QjwtCiAgTm90SW5kJT4lCiAgZmlsdGVyKFRvdGFsX0dhbWVzID49IDIwMDApJT4lCiAgbXV0YXRlKFRvdGFsX0dhbWVzID0gIkV4cGVyaWVuY2VkIikKCmBgYAoKClRoaXMgZGF0YSB3cmFuZ2xpbmcgc2hvd3MgdGhlIHNhbGFyeSBmb3IgdGhlIHdob2xlIGxlYWd1ZSwgYnV0IGl0IGlzIHNwbGl0IHVwIGludG8gdGhlIGV4cGVyaWVuY2VkIGFuZCBub3QgZXhwZXJpZW5jZWQgcGxheWVycy4KYGBge3J9CgpBbGxMZWFndWU8LQogIE5ld0IlPiUKICBmdWxsX2pvaW4oTm90TmV3QiwgYnkgPSBjKCJwbGF5ZXJJRCIsICJUb3RhbF9HYW1lcyIpKQpBbGxMZWFndWUKICAKCkFsbExNPC0gCiAgQWxsTGVhZ3VlJT4lCiAgbGVmdF9qb2luKE1vbmV5LCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKQpBbGxMTQoKVG90TGVhZ3VlPC0KICBBbGxMTSU+JQogIGxlZnRfam9pbihIYWxsT2ZGYW1lLCBieSA9IGMoInBsYXllcklEIiA9ICJwbGF5ZXJJRCIpKSU+JQogIGZpbHRlcihpbmR1Y3RlZCA9PSAiTiIpJT4lCiAgc2VsZWN0KHBsYXllcklELCB5ZWFySUQsIFRvdGFsX0dhbWVzLCBTYWxhcnkpClRvdExlYWd1ZQoKYGBgCgoKClRoaXMgam9pbiBvcGVyYXRpb24gd2lsbCBqb2luIHRoZSBIYWxsT2ZGYW1lIHRhYmxlIHdpdGggdGhlIEFsbHN0YXJGdWxsIHRhYmxlIHRvIGhlbHAgdXMgZmluZCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcGxheWVycyB0aGF0IG1hZGUgdGhlIEhhbGwgT2YgRmFtZSBhbmQgcGxheWVkIGluIEFsbCBTdGFyIEdhbWVzLiBXZSBjYW4gdXNlIHRoaXMgam9pbmVkIGRhdGEgc2V0IHRvIGZpZ3VyZSBvdXQgY29tbW9uYWxpdGllcyBiZXR3ZWVuIGFsbCBvZiB0aGUgSGFsbCBPZiBGYW1lIGJhc2ViYWxsIHBsYXllcnMuCmBgYHtyfQoKIyBKb2luIHRoZSBBbGxzdGFyRnVsbCB0YWJsZSB3aXRoIHRoZSBIYWxsT2ZGYW1lIHRhYmxlCkFsbFN0YXJIYWxsT2ZGYW1lSm9pbiA8LQogIEFsbHN0YXJGdWxsICU+JQogIGlubmVyX2pvaW4oSGFsbE9mRmFtZSwgYnkgPSBjKCJwbGF5ZXJJRCIgPSAicGxheWVySUQiKSkKCiMgVXNlIGRhdGEgd3JhbmdsaW5nIHRvIGFsdGVyIHRoZSB0YWJsZSB0byBmaW5kIHRoZSBhbW91bnQgb2YgdGltZXMgYW4gaW5kdWN0ZWQgcGxheWVycyBwbGF5ZWQgaW4gQWxsIFN0YXIgR2FtZXMKQWxsU3RhckhhbGxPZkZhbWVUYWJsZSA8LQogIEFsbFN0YXJIYWxsT2ZGYW1lSm9pbiAlPiUKICBmaWx0ZXIoaW5kdWN0ZWQgPT0gIlkiKSAlPiUKICBncm91cF9ieShwbGF5ZXJJRCwgaW5kdWN0ZWQpICU+JQogIHN1bW1hcmlzZShBcHBlYXJhbmNlQ291bnQgPSBuKCkpICU+JQogIGFycmFuZ2UoZGVzYyhBcHBlYXJhbmNlQ291bnQpKQogIApBbGxTdGFySGFsbE9mRmFtZVRhYmxlCgpgYGAKCgpUaGlzIGdncGxvdCBzaG93cyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBleHBlcmllbmNlZCBhbmQgaW5leHBlcmllbmNlZCBoYWxsIG9mIGZhbWUgcGxheWVyZXMuIFdlIGhhdmUgZmlsbGVkIHRoZWlyIGNvbG9yIGJ5IHRoZWlyIGV4cGVyaWVuY2UuIFRoZSBwbG90IG9uIHRoZSBncmFwaCBpcyBjb3JyZWxhdGVkIHRvIHRoZSB5ZWFyIHRoYXQgdGhleSB3ZXJlIGluZHVjdGVkLiAKYGBge3J9CgpBbGxIYWxsJT4lCmdncGxvdChhZXMoeCA9IHllYXJJRCwgeSA9IFNhbGFyeSwgY29sb3IgPSBUb3RhbF9HYW1lcykpKwogICBnZW9tX3BvaW50KCkrCiAgIGdlb21fc21vb3RoKCkrCiAgbGFicyh4ID0gIlllYXIgSW5kdWN0ZWQiLCB5ID0gIlRvdGFsIFNhbGFyeSIsIFRvdGFsX0dhbWVzID0gIkV4cGVyaWVuY2UgTGV2ZWwiKQoKYGBgCgoKVGhpcyBwbG90IGRpc3BsYXlzIHRoZSBzYWxhcmllcyBvZiBhbGwgdGhlIHBsYXllcnMgaW4gdGhlIGxlYWd1ZSB0aGF0IHdlcmUgbm90IGluZHVjdGVkIGludG8gdGhlIGhhbGwgb2YgZmFtZS4gV2UgY2FuIHNlZSB0aGF0IGluIHRoaXMgcGxvdCB0aGUgcGxheWVycyB3aXRoIG1vcmUgZXhwZXJpZW5jZSBhcmUgcmVjaWV2aW5nIG1vcmUgbW9uZXkuIFRvIGNvbXBhcmUgd2l0aCB0aGUgaGFsbCBvZiBmYW1lIHBsYXllcnMsIHdlIGNhbiBzZWUgdGhhdCBzb21lIHBsYXllcnMgdGhhdCBhcmUgbm90IGluZHVjdGVkIHRvIHRoZSBsZWFndWUgYXJlIHJlY2lldnZpbmcgbW9yZSBtb25leS4gSG93ZXZlciwgaXQgb3VyIGRhdGFzZXQgc29tZSBzYWxhcmllcyB3ZXJlIG1pc3NpZyB3aGljaCBjYW4gaGF2ZSBwbGF5ZXIgd2l0aCBoaWdoZXIgc2FsYXJpZXMgaW4gdGhlIGhhbGwgb2YgZmFtZSBhbmQganVzdCBpbiB0aGUgbGVhZ3VlLiAKYGBge3J9CgpUb3RMZWFndWUlPiUKZ2dwbG90KGFlcyh4ID0geWVhcklELCB5ID0gU2FsYXJ5LCBjb2xvciA9IFRvdGFsX0dhbWVzKSkrCiAgIGdlb21fcG9pbnQoKSsKICAgZ2VvbV9zbW9vdGgoKSsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiVG90YWwgU2FsYXJ5IChNaWxsaW9ucykiKQoKYGBgCgoKVGhlIHRhYmxlIGRpc3BsYXllZCBiZWxvdyB1c2VzIHJlZ3VsYXIgZXhwcmVzc2lvbnMgdG8gZGlzcGxheSB0aGUgaW5kdWN0ZWQgSGFsbCBvZiBGYW1lIHBsYXllcnMgd2hvIGhhZCBhIGJhdHRpbmcgYXZlcmFnZSBvZiA1MDAgb3IgbW9yZSBpbiBhdCBsZWFzdCAyMCBnYW1lcyBhbmQgeWVhcnMgdGhhdCBtYWRlIHRoZSBhY2hpZXZlbWVudC4gVGhpcyBoZWxwcyBzaG93IGhvdyBnb29kIHRoZSBpbmR1Y3RlZCBwbGF5ZXJzIGFyZSBhdCBiYXR0aW5nIGFuZCB0aGUgeWVhcnMgdGhhdCB0aGV5IGRpZCBpdCBpbi4KYGBge3J9CgpIYWxsT2ZGYW1lUGxheWVycyA8LQogIEhhbGxPZkZhbWUgJT4lCiAgZmlsdGVyKGluZHVjdGVkID09ICJZIikgJT4lCiAgc2VsZWN0KHBsYXllcklELCB5ZWFySUQpCgoKSGFsbE9mRmFtZUJhdHRpbmcgPC0KICBCYXR0aW5nICU+JQogIGlubmVyX2pvaW4oSGFsbE9mRmFtZVBsYXllcnMsIGJ5ID0gYygicGxheWVySUQiID0gInBsYXllcklEIikpCgoKSGFsbE9mRmFtZUJhdEF2ZyA8LQogIEhhbGxPZkZhbWVCYXR0aW5nICU+JQogIGZpbHRlcihHID4gMjApICU+JQogIHNlbGVjdChwbGF5ZXJJRCwgeWVhcklELngsIEFCKQoKCkhhbGxPZkZhbWVPdmVyNTAwIDwtCiAgSGFsbE9mRmFtZUJhdEF2ZyAlPiUKICBleHRyYWN0TWF0Y2hlcygiXihbNS05XXsxfVswLTldezJ9KS4qJCIsIEFCKSAlPiUKICBmaWx0ZXIoICEgaXMubmEobWF0Y2gxKSkKSGFsbE9mRmFtZU92ZXI1MDAKCmBgYAoKVGhlIGdyYXBoIGJlbG93IGlzIHRoZSBjb21wYXJpc29uIGJldHdlZW4gaW5kdWN0ZWQgSGFsbCBvZiBGYW1lIFBsYXllcnMuIFRoaXMgZ3JhcGggZGlzcGxheXMgdGhlIGFtb3VudCBvZiBwbGF5ZXJzIHRoYXQgcGxheWVkIGluIGNlcnRhaW4gYW1vdW50IG9mIEFsbCBTdGFyIEdhbWVzLCBpbmRpY2F0ZWQgYWxvbmcgdGhlIHgtYXhpcy4gVGhpcyBncmFwaCBoYXMgYSB5LWludGVyY2VwdCBvZiB0aGUgYXZlcmFnZSBhbW91bnQgb2YgYXBwZWFyYW5jZXMuIFRoaXMgYXZlcmFnZSBsaW5lIGhlbHBzIHVzIHVuZGVyc3RhbmQgaG93IGltcG9ydGFudCBBbGwgU3RhciBhcHBlYXJhbmNlcyB3ZXJlIGZvciBwbGF5ZXJzIGJlaW5nIGluZHVjdGVkIGludG8gSGFsbCBvZiBGYW1lLgpgYGB7cn0KCkFsbFN0YXJIYWxsT2ZGYW1lR3JhcGhEYXRhIDwtCiAgQWxsU3RhckhhbGxPZkZhbWVUYWJsZSAlPiUKICBncm91cF9ieShBcHBlYXJhbmNlQ291bnQpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSkKCkFsbFN0YXJIYWxsT2ZGYW1lR3JhcGggPC0KICBBbGxTdGFySGFsbE9mRmFtZUdyYXBoRGF0YSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBBcHBlYXJhbmNlQ291bnQsIHkgPSB0b3RhbCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gInJlZCIpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gbWVhbih0b3RhbCkpLCBjb2xvciA9ICJibHVlIikKCkFsbFN0YXJIYWxsT2ZGYW1lR3JhcGgKCmBgYAoKSW4gdGhlIGdyYXBoIGJlbG93LCB5b3UgY2FuIG5vdGljZSB0aGF0IHRoZSBhdmcgaG9tZXJ1bnMgcGVyIHllYXIgb2YgSGFsbCBvZiBGYW1lcnMgaXMgbG93ZXIgdGhhbiB0aGUgcmVzdCBvZiB0aGUgbGVhZ3VlLiBUaGlzIHdvdWxkIGluZGljYXRlIHRoYXQgSG9tZXJ1bnMgYXJlIG5vdCBhIGNydWNpYWwgc3RhdGlzdGljIGluIHRoZSBnYW1lIG9mIGJhc2ViYWxsIHRvIGdldCB5b3UgaW50byB0aGUgSGFsbCBvZiBGYW1lLgpgYGB7cn0KI0JhdHRpbmcgc3RhdHMKCkJhdHRpbmdBbmRIYWxsb2ZGYW1lIDwtIAogIEJhdHRpbmcgJT4lCiAgZnVsbF9qb2luKEhhbGxPZkZhbWUsIGJ5ID0gYygicGxheWVySUQiID0gInBsYXllcklEIikpICU+JQogIGZpbHRlcihpbmR1Y3RlZCA9PSAiWSIpCgojT25seSBUYWtlIHN0YXRzIHdpdGggcGxheWVycyBoYXZpbmcgbW9yZSB0aGFuIDIwIGdhbWVzCkJhdHRpbmdBbmRIYWxsb2ZGYW1lIDwtCiAgQmF0dGluZ0FuZEhhbGxvZkZhbWUgJT4lCiAgICBmaWx0ZXIoRyA+IDIwKSAKCkhhbGxPZkZhbWVySG9taWVzIDwtCiAgQmF0dGluZ0FuZEhhbGxvZkZhbWUgJT4lCiAgICBzZWxlY3QoeWVhcklELngsIEgpICU+JQogICAgZ3JvdXBfYnkoeWVhcklELngpICU+JQogICAgc3VtbWFyaXNlKEF2Z0hzSE9GID0gbWVhbihIKSkgJT4lCiAgICByZW5hbWUoeWVhcklEID0geWVhcklELngpCgpFdmVyeWJvZHlCYXR0aW5nIDwtCiAgQmF0dGluZyAlPiUKICAgIGZpbHRlcihHID4gMjApICU+JQogICAgc3VtbWFyaXNlKEF2Z0hvbWVSdW5QZXJQbGF5ZXJFdmVyeWJvZHkgPSBtZWFuKEgpKQoKR3JhcGhIb21lUnVucyA8LQogIEJhdHRpbmcgJT4lCiAgICBzZWxlY3QoeWVhcklELCBHLCBIKSAlPiUKICAgIGdyb3VwX2J5KHllYXJJRCkgJT4lCiAgICBmaWx0ZXIoRyA+IDIwKSAlPiUKICAgIHN1bW1hcmlzZShBdmdIc0V2ZXJ5ID0gbWVhbihIKSkKCiNXaGljaCBsZWFndWUgaGFzIGdyZWF0ZXIgSE9GIGNoYW5jZQpMZWFndWVGcm9tQW1lcmljYW4gPC0KICBCYXR0aW5nQW5kSGFsbG9mRmFtZSAlPiUKICAgIHNlbGVjdCh5ZWFySUQueCwgbGdJRCkgJT4lCiAgICBncm91cF9ieSh5ZWFySUQueCkgJT4lCiAgICBmaWx0ZXIobGdJRCA9PSAiQUEiKSAlPiUKICAgIHN1bW1hcmlzZShBbWVyaWNhbiA9IG4oKSkgJT4lCiAgICByZW5hbWUoeWVhcklEID0geWVhcklELngpCgpMZWFndWVGcm9tTmF0aW9uYWwgPC0KICBCYXR0aW5nQW5kSGFsbG9mRmFtZSAlPiUKICAgIHNlbGVjdCh5ZWFySUQueCwgbGdJRCkgJT4lCiAgICBncm91cF9ieSh5ZWFySUQueCkgJT4lCiAgICBmaWx0ZXIobGdJRCA9PSAiTkwiKSAlPiUKICAgIHN1bW1hcmlzZShOYXRpb25hbCA9IG4oKSkgJT4lCiAgICByZW5hbWUoeWVhcklEID0geWVhcklELngpCgpMZWFndWVHcmFwaCA8LQogIExlYWd1ZUZyb21BbWVyaWNhbiAlPiUKICAgIGZ1bGxfam9pbihMZWFndWVGcm9tTmF0aW9uYWwsIGJ5ID0gYygieWVhcklEIiA9ICJ5ZWFySUQiKSkKCiAKTGVhZ3VlR3JhcGgxIDwtCiAgIExlYWd1ZUdyYXBoICU+JQogICAgICBnYXRoZXIoa2V5ID0ga2luZCwgdmFsdWUgPSBUb3RhbCwgQW1lcmljYW4sIE5hdGlvbmFsKQoKTGVhZ3VlR3JhcGgxCgpHcmFwaDEgPC0KICBHcmFwaEhvbWVSdW5zICU+JQogICAgZnVsbF9qb2luKEhhbGxPZkZhbWVySG9taWVzLCBieSA9IGMoInllYXJJRCIgPSAieWVhcklEIikpCgpHcmFwaDEuMSA8LSAKICBHcmFwaDEgJT4lCiAgICBnYXRoZXIoa2V5ID0ga2luZCwgdmFsdWUgPSBBdmcsIEF2Z0hzSE9GLCBBdmdIc0V2ZXJ5KQoKCmdncGxvdChkYXRhPUdyYXBoMS4xLGFlcyh4PXllYXJJRCx5PUF2ZyAsZmlsbD1raW5kKSkrCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknLHBvc2l0aW9uPSdzdGFjaycsIHdpZHRoPS45KSsKICBnZ3RpdGxlKCJIT0YgVnMgRXZlcnlib2R5IEhvbWVydW5zIikKCmBgYAoKCg==